最後更新日:2023/01/09
[Service Worker]使用.Net Core快速實作瀏覽器推播(Push Notifications)功能
瀏覽器推播通知(Push Notifications)對於網站製作者來說是個很好的功能,當使用者允許通知後,無論他有沒有停留在網站上,或是沒在用手機,都可以像APP通知那樣,將更新內容傳送給使用者,進而維持黏著度,以下就讓我們來快速的製作這個功能吧。
推播通知是利用了Service Worker,也就是瀏覽器的背景來執行運作的,要完成使用者訂閱、網站端發通知、使用者接收,需要下面幾個步驟:
- 準備好serviceWorker.js檔案,並放在網站根目錄。
- 取得VPID金鑰,防止任何人都可以傳送通知給這個使用者。
- 準備好一個html檔案,放置一個按鈕,撰寫相關javascript,使用者按下後會詢問是否給予通知的權限。
- 得到使用者權限後,取得回傳的endPoint、p256dh、auth值。
- 使用.Net Core來發送通知給使用者。
讓我們來開始吧!
1.準備好serviceWorker.js,並放在網站根目錄。
this.addEventListener('install', function(event) { console.log('安裝service wroker'); }); this.addEventListener('activate', function(event){ console.log('service wroker已啟動!') }); this.addEventListener('fetch', function(event) { console.log('Handling fetch event for', event.request.url); }); // controlling service worker this.addEventListener("message", function(e) { // e.source is a client object e.source.postMessage("Hello! Your message was: " + e.data); }); this.onpush = function(event) { console.log(event.data); // From here we can write the data to IndexedDB, send it to any open // windows, display a notification, etc. } this.addEventListener('push', function (e) { var body; if (e.data) { body = e.data.text(); } else { body = "Standard Message"; } var options = { body: body, icon: "/assets/img/xxxxx.jpeg", //顯示網站LOGO 絕對或相對路徑都可 image: '/assets/img/xxxxx.jpeg', //顯示通知的圖片 絕對或相對路徑都可 vibrate: [100, 50, 100], data: { dateOfArrival: Date.now() }, actions: [ { action: "explore", title: "瀏覽最新文章", icon: "images/checkmark.png" //按鈕的icon圖 絕對或相對路徑都可 }, { action: "close", title: "關閉", icon: "images/red_x.png" //按鈕的icon圖 絕對或相對路徑都可 }, ] }; e.waitUntil( self.registration.showNotification("露西的爹有新文章囉", options) ); }); this.addEventListener('notificationclick', function (e) { var notification = e.notification; var action = e.action; if (action === 'close') { notification.close(); } else { // 按下瀏覽最新文章要做的動作 clients.openWindow('https//www.lucysdad.com'); notification.close(); } });
2.取得VPID金鑰,防止任何人都可以傳送通知給這個使用者,可直接上這個網站線上產生公鑰及私鑰,並留存等下使用。
3.準備好一個html檔案,放置一個按鈕,並設定click後要執行的function。
<button type="button" onclick="InstallServiceWorker()">
4.撰寫相關javascript,使用者按下後會詢問是否給予通知的權限。
function InstallServiceWorker() { if ('serviceWorker' in navigator) { //判斷瀏覽器是否支援serviceWorker navigator.serviceWorker .register('/serviceworker.js') // 註冊 Service Worker 路徑為第一步驟的serviceworker.js .then(function (reg) { //console.log('Registration succeeded. Scope is ' + reg.scope); // 註冊成功 取消註解後會印出service worker可使用的範圍 //註冊後判斷使用者是否之前已經訂閱過了 if (Notification.permission === "granted") { console.log("已經訂閱過了"); alert("您已經訂閱過囉"); getSubscription(reg); } else if (Notification.permission === "blocked") { console.log("之前拒絕了訂閱"); //可跳訊息視窗告知如何重新訂閱 } else { console.log("還沒訂閱過"); requestNotificationAccess(reg); //顯示訂閱視窗 } }) .catch(function (error) { console.log('Registration failed with ' + error); // 註冊失敗 }); } else { //瀏覽器不支援serviceWorker 可能是版本太舊 alert("很抱歉,您的瀏覽器不支援訂閱的功能,請升級您的瀏覽器。"); } } function requestNotificationAccess(reg) { Notification.requestPermission(function (status) { if (status == "granted") { //console.log("使用者按下訂閱了"); var options = { body: '您已成功訂閱露西的爹!', icon: '/assets/img/_____.jpg' //顯示網站LOGO 絕對或相對路徑都可 } new Notification('訂閱完成!!', options); //即時發送一個通知,告訴使用者已完成訂閱 getSubscription(reg); } else { //console.log("使用者拒絕了訂閱"); } }); } function getSubscription(reg) { reg.pushManager.getSubscription().then(function (sub) { if (sub === null) { reg.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: "BAEhJJK8pqg33cGF4pWcY.......HXNjUPtteNHcCf01jBVWY7018oQm9zQ" //這是步驟2所取得到的 public Key }).then(function (sub) { fillSubscribeFields(sub); }).catch(function (e) { console.error("Unable to subscribe to push", e); }); } else { fillSubscribeFields(sub); } }); } function fillSubscribeFields(sub) { //步驟五所提到的 得到使用者權限後,取得回傳的endPoint、p256dh、auth值 //可自行將這三個值透過ajax存入您的資料庫 console.log("sub.endpoint:" + sub.endpoint); //endPoint為要傳送通知時,每個人都有不同的api網址 console.log("p256dh:" + arrayBufferToBase64(sub.getKey("p256dh"))); console.log("auth:" + arrayBufferToBase64(sub.getKey("auth"))); } function arrayBufferToBase64(buffer) { var binary = ''; var bytes = new Uint8Array(buffer); var len = bytes.byteLength; for (var i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]); } return window.btoa(binary); }
5.得到使用者權限後,取得回傳的endPoint、p256dh、auth值,這部分已在上一步驟的fillSubscribeFields function裡完成。
6.使用.Net Core來發送通知給使用者,請先安裝WebPush-NetCore套件,接者撰寫以下程式。
var subject = "mailto:XXXXX@gmail.com"; //申請VAPID所輸入的email var publicKey = "BAHWfhher623h....cfhFjFUjNKs"; //步驟2所取得到的 public Key var privateKey = "privateKey-privateKey-privateKey-privateKey"; //步驟2所取得到的 private Key var vapidDetails = new VapidDetails(subject, publicKey, privateKey); PushSubscription subscription = new PushSubscription( "https://fcm.googleapis.com/fcm/send/......", //步驟5得到的endPoint值 "BAct3KDe0CyW6Cc1De0CyW6CPxy.......De0CyW6C", //步驟5得到的p256dh值 "HRIePb8....UlftQ=="); //步驟5得到的auth值 var webPushClient = new WebPushClient(); try { webPushClient.SendNotification(subscription, "[居家風水]告別2022!2023年九宮飛星開運風水佈局", vapidDetails); } catch (Exception) { }
搞定收工,使用者收到的通知樣式可以在步驟一的this.addEventListener('push', function (e) {}監聽事件裡面完成。
本篇只是快速的帶各位完成使用者訂閱及網站端發送通知的功能,其中service worker的生命週期、使用範圍、監聽事件等等,有很多原理可以自行去研究,精進自己的程式能力。
參考網站:
https://blog.elmah.io/how-to-send-push-notifications-to-a-browser-in-asp-net-core/
https://ithelp.ithome.com.tw/users/20117813/ironman/2219
https://www.cythilya.tw/2018/02/17/firebase-push-notification/
0 則留言
露西的爹
Hi,我是露西的老爹,無聊時寫寫文章分享很多有用的資訊。
有新文章就會馬上通知哦!